package com.mf.service.utils.numericalProcedure;

import com.mf.bo.calculateHistory.*;
import com.mf.service.IWeekCodeHistoryService;
import com.mf.service.utils.numericalProcedure.CalculateProcedure.CalculateProcedure;
import com.mf.vo.KDJVo;
import com.mf.vo.StockGatherVo;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: lmf
 * @Create: 2024/6/13 21:08
 * Description:  基础计算
 */
public class BasicNumerical {

    /**
     * 计算方案是否合理
     *
     * @param stockGatherVo 指标集合
     * @return 符合条件list集合
     */
    public static CalculateHistoryBo Calculate(StockGatherVo stockGatherVo, CalculateProcedure calculateProcedure) {
        final List<KDJVo> kdj = stockGatherVo.getKdj();
        if (kdj == null || kdj.size() < 30) {
            return null;
        }
        // 代码计算的集合
        CalculateHistoryBo calculateHistoryBo = new CalculateHistoryBo();
        calculateHistoryBo.setDm(stockGatherVo.getDm());
        // 获取到历史数据从30天开始 到前 3 天计算结束
        for (int i = 30; i < kdj.size() - 10; i++) {

            // 计算收盘后第二天是否可买入
            final String calculate3 = calculateProcedure.isBuyableDay(stockGatherVo, i);
            // 符合条件
            if (null != calculate3) {
                if (calculateHistoryBo.getProfitBoList() == null) {
                    calculateHistoryBo.setProfitBoList(new ArrayList<>());
                    calculateHistoryBo.setFailList(new ArrayList<>());
                    calculateHistoryBo.setSuccessList(new ArrayList<>());
                }

                // 判断当天是否盈利
                final ProfitBo historyBo = calculateProcedure.getProfitBo(stockGatherVo, i, calculateHistoryBo);

                calculateHistoryBo.getProfitBoList().add(historyBo);
                // 区分记录成功失败的案例
                if (historyBo.getIsProfit() == 1) {
                    calculateHistoryBo.getSuccessList().add(historyBo);
                } else {
                    calculateHistoryBo.getFailList().add(historyBo);
                }

                // 如果符合条件 跳过3天( 买入后3天之内不在买入 )
                // 不符合实际 正常情况下看不出来
                // i = i + 3;
            }
        }

        return calculateHistoryBo;
    }


    /**
     * 将总的结果按照日期进行分组
     *
     * @param calculateHistoryBoList 股票的计算结果
     * @return 分组后的结果
     */
    public static List<SumDateCalculateBo> getSumDateCalculateBo(List<CalculateHistoryBo> calculateHistoryBoList,
                                                                 ProfitBoListExtractor profitBoListExtractor) {
        HashMap<String, List<String>> hashMap = new HashMap<>();

        for (CalculateHistoryBo historyBo : calculateHistoryBoList) {
            // 获取传入类型的数组列表
            List<ProfitBo> list = profitBoListExtractor.extractList(historyBo);
            if (list != null) {
                for (ProfitBo o : list) {
                    String date = o.getDate();
                    String dm = historyBo.getDm();
                    // 将dm添加到对应日期的列表中
                    hashMap.computeIfAbsent(date, k -> new ArrayList<>()).add(dm);
                }
            }
        }

        // 将map类型转换为List类型
        List<SumDateCalculateBo> calculateBoList = new ArrayList<>();
        for (Map.Entry<String, List<String>> entry : hashMap.entrySet()) {
            SumDateCalculateBo calculateBo = new SumDateCalculateBo();
            calculateBo.setDate(entry.getKey());
            calculateBo.setDm(entry.getValue());
            calculateBoList.add(calculateBo);
        }

        // 按日期进行排序
        calculateBoList.sort(Comparator.comparing(SumDateCalculateBo::getDate));
        return calculateBoList;
    }

    /**
     * @param calculateHistoryBoList 单只股票的计算结果
     * @return 总体结果计算
     */
    public static SumCalculateHistoryBo getSumCalculateHistoryBo(List<CalculateHistoryBo> calculateHistoryBoList) {
        final SumCalculateHistoryBo historyBo = new SumCalculateHistoryBo();

        int totalCount = 0;
        int profitCount = 0;
        int failCount = 0;
        int stopLossCount = 0;
        for (CalculateHistoryBo calculateHistoryBo : calculateHistoryBoList) {
            totalCount += calculateHistoryBo.getTotalCount();
            profitCount += calculateHistoryBo.getProfitCount();
            failCount += calculateHistoryBo.getFailCount();
            stopLossCount += calculateHistoryBo.getStopLossCount();
        }
        historyBo.setTotalCount(totalCount);
        historyBo.setProfitCount(profitCount);
        historyBo.setFailCount(failCount);
        historyBo.setStopLossCount(stopLossCount);
        // 所有股票将日期进行分组并排序
        historyBo.setSumDateCalculateBoList(BasicNumerical.getSumDateCalculateBo(calculateHistoryBoList,
                CalculateHistoryBo::getProfitBoList));
        // 成功的排序集合
        historyBo.setSumDateCalculateBoListSuccess(BasicNumerical.getSumDateCalculateBo(calculateHistoryBoList,
                CalculateHistoryBo::getSuccessList));
        // 失败的排序集合
        historyBo.setSumDateCalculateBoListFail(BasicNumerical.getSumDateCalculateBo(calculateHistoryBoList,
                CalculateHistoryBo::getFailList));

        // 计算盈利集合
        historyBo.setProfitGatherBoList(dateClassifier(historyBo.getSumDateCalculateBoList()));
        return historyBo;
    }

    /**
     * 将计算结果按照年、月进行分类
     */

    public static List<ProfitGatherBo> dateClassifier(List<SumDateCalculateBo> sumDateCalculateBoList) {
        // 创建一个Map来保存按年和月分类的数据
        Map<String, Map<String, List<SumDateCalculateBo>>> classifiedData = new LinkedHashMap<>();

        // 遍历原始数据
        for (SumDateCalculateBo item : sumDateCalculateBoList) {
            String dateStr = item.getDate();
            String year = dateStr.substring(0, 4);
            String month = dateStr.substring(5, 7);

            classifiedData
                    .computeIfAbsent(year, k -> new LinkedHashMap<>())
                    .computeIfAbsent(month, k -> new ArrayList<>())
                    .add(item);
        }

        List<ProfitGatherBo> profitGatherBoList = new ArrayList<>();
        // 构建 ProfitGatherBo 对象
        for (Map.Entry<String, Map<String, List<SumDateCalculateBo>>> yearEntry : classifiedData.entrySet()) {
            ProfitGatherBo profitGatherBoListYear = new ProfitGatherBo();
            profitGatherBoListYear.setDate(yearEntry.getKey());

            List<ProfitGatherBo> a = yearEntry.getValue().entrySet().stream().map(monthEntry -> {
                ProfitGatherBo profitGatherBoListMonth = new ProfitGatherBo();
                profitGatherBoListMonth.setDate(monthEntry.getKey());

                List<ProfitGatherBo> b = monthEntry.getValue().stream().map(item -> {
                    ProfitGatherBo profitGatherBoListDate = new ProfitGatherBo();
                    profitGatherBoListDate.setDate(item.getDate());
                    profitGatherBoListDate.setDms(item.getDm());
                    return profitGatherBoListDate;
                }).collect(Collectors.toList());

                profitGatherBoListMonth.setProfitGatherBosList(b);
                return profitGatherBoListMonth;
            }).collect(Collectors.toList());

            profitGatherBoListYear.setProfitGatherBosList(a);
            profitGatherBoList.add(profitGatherBoListYear);
        }
        return profitGatherBoList;
    }
}
